package cn.qianxun.meta.config.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.qianxun.meta.common.core.dto.RowsData;
import cn.qianxun.meta.common.core.utils.StringUtils;
import cn.qianxun.meta.common.core.web.vo.RemoveLongDTO;
import cn.qianxun.meta.config.dto.AddSysConfigDTO;
import cn.qianxun.meta.config.dto.SysConfigQueryDTO;
import cn.qianxun.meta.config.entity.SysConfig;
import cn.qianxun.meta.config.mapper.SysConfigMapper;
import cn.qianxun.meta.config.vo.SysConfigVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import cn.qianxun.meta.common.core.constant.Constants;
import cn.qianxun.meta.common.core.constant.UserConstants;
import cn.qianxun.meta.common.core.exception.ServiceException;
import cn.qianxun.meta.common.satoken.utils.LoginHelper;
import cn.qianxun.meta.config.service.ISysConfigService;
import cn.qianxun.meta.redis.utils.RedisUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author fuzhilin
 * @Date 2023/16/35
 * @Description
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class SysConfigServiceImpl extends ServiceImpl<SysConfigMapper, SysConfig> implements ISysConfigService {
    private final SysConfigMapper sysConfigMapper;

    @Override
    public String selectConfigByKey(String configKey) {
        String configValue = Convert.toStr(RedisUtils.getCacheObject(getCacheKey(configKey)));
        if (StringUtils.isNotEmpty(configValue)) {
            return configValue;
        }
        SysConfig config = new SysConfig();
        config.setConfigKey(configKey);
        SysConfig retConfig = sysConfigMapper.selectOne(new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getConfigKey, configKey).orderByDesc(SysConfig::getCreateTime).last("limit 1"));
        if (ObjectUtil.isNotNull(retConfig)) {
            RedisUtils.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue());
            return retConfig.getConfigValue();
        }
        return StringUtils.EMPTY;
    }

    @Override
    public RowsData<SysConfigVO> selectConfigList(SysConfigQueryDTO dto) {
        Page<Object> page = PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        List<SysConfigVO> list = sysConfigMapper.selectConfigList(dto);
        return new RowsData<SysConfigVO>(list, page.getTotal(), dto.getPageNum());
    }

    @Override
    public SysConfigVO details(String configId) {
        SysConfigVO configDTO = new SysConfigVO();
        SysConfig config = sysConfigMapper.selectById(configId);
        if (ObjectUtil.isNull(config)) {
            throw new ServiceException("所查配置参数不存在");
        }
        BeanUtils.copyProperties(config, configDTO);
        return configDTO;
    }

    @Override
    public void addConfig(AddSysConfigDTO dto) {
        SysConfig config = new SysConfig();
        BeanUtils.copyProperties(dto, config);
        if (UserConstants.NOT_UNIQUE.equals(checkConfigKeyUnique(config))) {
            throw new ServiceException("新增参数'" + config.getConfigName() + "'失败，参数键名已存在");
        }
        config.setCreateBy(LoginHelper.getLoginUser().getUserName());
        config.setCreateTime(new Date());
        int row = sysConfigMapper.insert(config);
        if (row > 0) {
            RedisUtils.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
        }
    }

    @Override
    public void editConfig(AddSysConfigDTO dto) {
        SysConfig config = new SysConfig();
        BeanUtils.copyProperties(dto, config);
        if (UserConstants.NOT_UNIQUE.equals(checkConfigKeyUnique(config))) {
            throw new ServiceException("修改参数'" + config.getConfigName() + "'失败，参数键名已存在");
        }
        config.setUpdateBy(LoginHelper.getLoginUser().getUserName());
        config.setUpdateTime(new Date());
        int row = sysConfigMapper.updateById(config);
        if (row > 0) {
            RedisUtils.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
        }
    }

    @Override
    public void deleteConfigByIds(RemoveLongDTO dto) {
        int count = sysConfigMapper.deleteConfigByIds(dto.getRemoveIdList());
        if (count > 0) {
            Collection<String> keys = RedisUtils.keys(Constants.SYS_CONFIG_KEY + "*");
            RedisUtils.deleteObject(keys);
        }
    }

    @Override
    public void clearCache() {
        Collection<String> keys = RedisUtils.keys(Constants.SYS_CONFIG_KEY + "*");
        RedisUtils.deleteObject(keys);
    }

    @Override
    public Map<String, List<SysConfigVO>> configList() {
        List<SysConfigVO> sysDtos = sysConfigMapper.selectList(new QueryWrapper<>()).stream().map(sysConfig -> {
            SysConfigVO dto = new SysConfigVO();
            BeanUtils.copyProperties(sysConfig, dto);
            return dto;
        }).collect(Collectors.toList());
        Set<String> configKeys = sysDtos.stream().map(SysConfigVO::getConfigKey).collect(Collectors.toSet());
        Map<String, List<SysConfigVO>> map = new HashMap<>(configKeys.size());
        List<SysConfigVO> sysConfigDTOS;
        for (String configKey : configKeys) {
            sysConfigDTOS = sysDtos.stream().filter(sysConfigDTO -> sysConfigDTO.getConfigKey().equals(configKey)).collect(Collectors.toList());
            map.put(configKey, sysConfigDTOS);
        }
        log.info("系统参数map：{}", map);
        return map;
    }

    /**
     * 设置cache key
     *
     * @param configKey 参数键
     * @return 缓存键key
     */
    private String getCacheKey(String configKey) {
        return Constants.SYS_CONFIG_KEY + configKey;
    }


    /**
     * 校验参数键名是否唯一
     *
     * @param config 参数配置信息
     * @return 结果
     */
    public String checkConfigKeyUnique(SysConfig config) {
        Long configId = ObjectUtil.isNull(config.getConfigId()) ? -1L : config.getConfigId();
        SysConfig info = sysConfigMapper.selectOne(new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getConfigKey, config.getConfigKey()).last("limit 1"));
        if (ObjectUtil.isNotNull(info) && info.getConfigId().longValue() != configId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }
}
